package com.lintf.system.service.wechat.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.lintf.common.core.domain.model.WxLoginBody;
import com.lintf.common.utils.sign.Base64;
import com.lintf.system.service.wechat.IWeChatService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * @ system:Mac
 * @ author:lin tingfeng
 * @ data:2024/1/16 15:01
 * @ package_name:com.lintf.system.service.weChat.impl
 * @ project_name:mobile-project
 * @ desc:
 */
@Slf4j
@Service
public class IWeChatServiceImpl implements IWeChatService {

    @Value("${wx.url}")
    private String url;
    @Value("${wx.appid}")
    private String appid;
    @Value("${wx.appSecret}")
    private String appSecret;
    @Autowired
    private RestTemplate restTemplate;

    private String accessToken;
    private long accessTokenTimestamp = 0;
    private long accessTokenExpiresIn = 0;

    @Override
    public Map<String, Object> wxLogin(WxLoginBody wxLoginBody) {
        String code = wxLoginBody.getCode();
        String encryptedIv = wxLoginBody.getEncryptedIv();
        String encryptedData = wxLoginBody.getEncryptedData();
        StringBuilder requestUrl = new StringBuilder()
                .append(url)
                .append("&appid=")
                .append(appid)
                .append("&secret=")
                .append(appSecret)
                .append("&js_code=")
                .append(code);
        String res = restTemplate.getForObject(requestUrl.toString(), String.class);
        JSONObject parseObject = JSONObject.parseObject(res);
        String sessionKey = parseObject.getString("session_key");
        String openid = parseObject.getString("openid");
        String decryptResult = "";
        if (wxLoginBody.getCheckSession()) {
            try {
                decryptResult = decrypt(sessionKey, encryptedIv, encryptedData);
            } catch (Exception e) {
                log.error("调取微信登录失败！正在重试！");
            }
        }
        Map<String, Object> result = new HashMap<>();
        result.put("decryptResult", decryptResult);
        result.put("openid", openid);
        return result;
    }

    /**
     * AES解密
     */
    private String decrypt(String sessionKey, String encryptedIv, String encryptedData) throws Exception {
        // 转化为字节数组
        byte[] key = Base64.decode(sessionKey);
        byte[] iv = Base64.decode(encryptedIv);
        byte[] encData = Base64.decode(encryptedData);
        // 假如密钥缺乏16位，那么就补足
        int base = 16;
        if (key.length % base != 0) {
            int groups = key.length / base + (key.length % base != 0 ? 1 : 0);
            byte[] temp = new byte[groups * base];
            Arrays.fill(temp, (byte) 0);
            System.arraycopy(key, 0, temp, 0, key.length);
            key = temp;
        }
        // 假如初始向量缺乏16位，也补足
        if (iv.length % base != 0) {
            int groups = iv.length / base + (iv.length % base != 0 ? 1 : 0);
            byte[] temp = new byte[groups * base];
            Arrays.fill(temp, (byte) 0);
            System.arraycopy(iv, 0, temp, 0, iv.length);
            iv = temp;
        }
        AlgorithmParameterSpec ivSpec = new IvParameterSpec(iv);
        String resultStr = null;
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
            resultStr = new String(cipher.doFinal(encData), "UTF-8");
        } catch (Exception e) {
            //            logger.info("解析错误");
            e.printStackTrace();
        }
        // 解析加密后的字符串
        return resultStr;
    }

    /**
     * 获取accesstoken
     *
     * @return
     */
    @Override
    public String getAccessToken() {
        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + appSecret;
        if (isAccessTokenExpired()) {
            log.info("======检测到accessToken已过期======");
            log.info("======正在请求新的accessToken======");
            try {
                String resultString = restTemplate.getForObject(url, String.class);
                log.info("获取微信accessToken:{}", resultString);
                if (StringUtils.isNotEmpty(resultString)) {
                    JSONObject jsonObject = JSON.parseObject(resultString);
                    accessToken = jsonObject.get("access_token").toString();
                    updateAccessTokenExpirationTime(Long.parseLong(jsonObject.get("expires_in").toString()));
                } else {
                    log.error("返回值为空，请检查请求报文或者请求地址是否正确");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        log.info("======成功获取到accessToken======");
        return accessToken;
    }

    private boolean isAccessTokenExpired() {
        // 根据实际需求，判断 accessToken 是否已过期
        // 可以通过记录 accessToken 的获取时间和有效期，与当前时间进行对比来判断是否过期
        long currentTime = System.currentTimeMillis() / 1000;  // 获取当前时间戳（单位：秒）
        return (accessTokenTimestamp + accessTokenExpiresIn) < currentTime;
    }

    private void updateAccessTokenExpirationTime(long expiresIn) {
        // 更新 accessToken 的过期时间
        accessTokenTimestamp = System.currentTimeMillis() / 1000;  // 记录更新时间戳（单位：秒）
        accessTokenExpiresIn = expiresIn;
    }
}
